from collections import Counter

from django.shortcuts import render, get_object_or_404, redirect
from django.contrib import admin
from django.core.exceptions import PermissionDenied
from django.utils.translation import gettext_lazy as _

from app import settings
from app.common import get_client_ip

from .models import Stat, Link
from .utils import get_ip_info, get_device_type, user_agent_parser, get_referer
from .forms import LinkPasswordForm


def go_page(request, slug):

    link = get_object_or_404(Link, slug=slug)
    raw_user_agent = request.META.get('HTTP_USER_AGENT', None)
    client_ip = get_client_ip(request)

    referer = get_referer(request)
    print('referer 1:', referer)

    context = {
        'link': link,
        'referer': referer
    }

    if raw_user_agent is not None and client_ip is not None:
        user_agent = user_agent_parser(raw_user_agent)

        # Deny bots
        if user_agent.is_bot:
            raise PermissionDenied()

        if link.is_active():
            # if the link has a password
            if link.password:
                if request.method == 'POST':
                    form = LinkPasswordForm(request.POST)
                    if form.is_valid() and link.password == form.cleaned_data['password']:
                        # Register new stats
                        country, device_type, platform = link.register_stats(
                            request, user_agent)

                        # Redirection
                        if link.link_type == link.TYPES.DIRECT and link.is_able_to_redirect():
                            # Checking country, platform, device
                            return redirect(link.get_final_url(country, device_type, platform))
                    else:
                        context['message'] = _("Incorrect Password!")
                else:
                    form = LinkPasswordForm()
                context['form'] = form

            else:  # No password found
                # Register new stats
                country, device_type, platform = link.register_stats(
                    request, user_agent)

                # Redirection
                if link.link_type == link.TYPES.DIRECT and link.is_able_to_redirect():
                    # Checking country, platform, device
                    return redirect(link.get_final_url(country, device_type, platform))

        if not link.is_active():
            context['message'] = _('The link is unavailable right now!')
        elif link.is_expired() or link.is_max_clicks_reached():
            context['message'] = _('The link is expired!')

    return render(request, 'go.html', context)


def stats(request, link_id):
    context = dict(admin.site.each_context(request))

    link = get_object_or_404(Link, id=link_id)

    # Check Link permissions for the logged in user.
    if not (request.user == link.user or request.user.has_perm('%s.view_%s' % (link._meta.app_label, link._meta.model_name), link)):
        raise PermissionDenied

    stat_list = link.stats.all()

    clicks_over_time = Counter((stat.created.strftime('%Y-%m-%d')
                                for stat in stat_list))
    clicks_over_time = sorted(
        clicks_over_time.items(), key=lambda item: item[0])

    top_all_countries = Counter((stat.country for stat in stat_list))
    top_all_countries = sorted(top_all_countries.items(),
                               key=lambda item: item[1], reverse=True)

    top_countries_total_clicks = sum(
        clicks for _, clicks in top_all_countries)

    top_countries = top_all_countries[:settings.MAX_ITEMS]
    top_countries = [(country, clicks, round(clicks * 100 / top_countries_total_clicks, 1))
                     for country, clicks in top_countries]

    top_browsers = Counter((stat.browser for stat in stat_list))
    top_browsers = sorted(top_browsers.items(),
                          key=lambda item: item[1], reverse=True)[:settings.MAX_ITEMS]

    top_os = Counter((stat.os for stat in stat_list))
    top_os = sorted(top_os.items(),
                    key=lambda item: item[1], reverse=True)[:settings.MAX_ITEMS]

    top_devices = Counter((stat.device for stat in stat_list))
    top_devices = sorted(top_devices.items(),
                         key=lambda item: item[1], reverse=True)[:settings.MAX_ITEMS]

    # TODO: caching is needed
    referers = Counter((stat.referer for stat in stat_list))
    referers = sorted(referers.items(),
                      key=lambda item: item[1], reverse=True)[:settings.MAX_ITEMS]

    context.update({
        'link': link,
        'stat_list': stat_list,
        'clicks_over_time': clicks_over_time,
        'top_countries': top_countries,
        'top_all_countries': top_all_countries,
        'top_browsers': top_browsers,
        'top_os': top_os,
        'top_devices': top_devices,
        'referers': referers
    })

    return render(request, 'stats.html', context)
